#pragma once

#include <dinput.h>
#include "qobject.h"
#include "qvector.h"

class Joystick :
	public QObject
{
	Q_OBJECT
	class Input 
	{
		GUID _guid;
		int _offset;
		int _flags;
		int _type;
		DIOBJECTDATAFORMAT _fmt;
	public:
		Input(int offset, int type, int flags, const GUID &guid) 
		{
			_fmt.dwOfs = _offset = offset;
			_fmt.dwFlags = _flags = flags;
			_fmt.dwType = _type = type;
			_guid.Data1 = guid.Data1;
			_guid.Data2 = guid.Data2;
			_guid.Data3 = guid.Data3;
			_guid.Data4[0] = guid.Data4[0];
			_guid.Data4[1] = guid.Data4[1];
			_guid.Data4[2] = guid.Data4[2];
			_guid.Data4[3] = guid.Data4[3];
			_guid.Data4[4] = guid.Data4[4];
			_guid.Data4[5] = guid.Data4[5];
			_guid.Data4[6] = guid.Data4[6];
			_guid.Data4[7] = guid.Data4[7];
			_fmt.pguid = &_guid;
		}
		~Input() {}

		int getOffset() { return _offset; }
		int getFlags() { return _flags; }
		int getType() { return _type; }
		const GUID *getGuid() { return &_guid; }
		LPCDIOBJECTDATAFORMAT getObjectFmt() { return &_fmt; }
	};

	char *_prevState;
	char *_currState;
	unsigned int _bufferSize;
	DIDATAFORMAT _dataFormat;
	IDirectInputDevice8 *_dev;
	QVector<Input *> _inputVector;
	DIOBJECTDATAFORMAT *_devObjectFormat;

public:
	Joystick(IDirectInputDevice8 *dev);
	~Joystick(void);
	void setupDevice();
	void poll();

signals:
	void axisChanged(int axis, int value);
	void keyDown(int keyCode);
	void keyUp(int keyCode);

private:
	static int DIEnumDeviceObjectsCallback(LPCDIDEVICEOBJECTINSTANCE lpddoi, void *thisPtr);

};

class JoystickException
{
	HRESULT _errorCode; 
	QString _message;
public:
	JoystickException(HRESULT error) : _errorCode(error) {}
	virtual ~JoystickException(){}

	HRESULT getCode() { return _errorCode; }
	const QString& getMessage() { return _message; }
};

class JoystickSetupException 
	: public JoystickException
{
public:
	JoystickSetupException(HRESULT error) : JoystickException(error) {}
};

class JoystickPollingException 
	: public JoystickException
{
public:
	JoystickPollingException(HRESULT error) : JoystickException(error) {}
};